package org.jeecg.common.rc.ignoretoken;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zjarlin
 */
@Component
@Slf4j
public class NoTokenMapFinder {
    @Autowired
    ApplicationContext applicationContext;

    /**
     * 获取代理对象的原始对象
     * @param bean 入参
     * @return {@link Object }
     * @author zjarlin
     * @since 2023/11/22
     */

    public static Object getTargetBean(Object bean) {
        Object targetBean = bean;
        if (targetBean instanceof Advised) {
            try {
                Object target = ((Advised) targetBean).getTargetSource().getTarget();
                targetBean = target;
            } catch (Exception e) {

            }
        }
        return targetBean;
    }

    /**
     * 获取加了特定注解的方法集合
     *
     * @param annotationType 入参
     * @return {@link Map }<{@link String }     方法rest路径
     * , {@link Method }>  方法
     * @author zjarlin
     * @since 2023/11/22
     */

    public Map<String, String> findSkipRestUrlMap(Class<? extends Annotation> annotationType) {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RestController.class);


        Map<String, String> resultMap = beansWithAnnotation.values().stream()
                .filter(value -> {
                    //获取代理对象的原始对象,不然反射拿不到注解
                    Object targetBean = getTargetBean(value);
                    Class<?> controllerClass = targetBean.getClass();
                    RequestMapping controllerRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
                    return Objects.nonNull(controllerRequestMapping);
                })
                .flatMap(value -> {
                    //获取代理对象的原始对象,不然反射拿不到注解
                    Object targetBean = getTargetBean(value);
                    Class<?> controllerClass = targetBean.getClass();
                    RequestMapping controllerRequestMapping = controllerClass.getAnnotation(RequestMapping.class);
                    String controllerPath = Arrays.stream(controllerRequestMapping.value())
                            .map(e -> StrUtil.addPrefixIfNot(e, "/"))
                            .findAny().orElse("");

                    boolean annotated4Controller = AnnotatedElementUtils.isAnnotated(controllerClass, annotationType);
                    if (annotated4Controller) {
                        AbstractMap<String, String> stringStringHashMap = new HashMap<>();
                        String s = StrUtil.removeSuffix(controllerPath, "/");
                        String s1 = StrUtil.addSuffixIfNot(s, "/**");
                         stringStringHashMap.put(s1,  "anon");
                        return stringStringHashMap.entrySet().stream();

                    }
                    Method[] methods = controllerClass.getMethods();

                    return Arrays.stream(methods)
                            .filter(m -> {
                                boolean annotated = AnnotatedElementUtils.isAnnotated(m, annotationType);
                                boolean annotated1 = AnnotatedElementUtils.isAnnotated(m, RequestMapping.class);
                                return annotated && annotated1;
                            })
                            .collect(Collectors.toMap(m -> {
                                RequestMapping mergedAnnotation = AnnotatedElementUtils.findMergedAnnotation(m, RequestMapping.class);
                                String methodPath = Arrays.stream(mergedAnnotation != null ? mergedAnnotation.value() : new String[0])
                                        .findAny()
                                        .map(e -> StrUtil.addPrefixIfNot(e, "/"))
                                        .orElse("");
                                return controllerPath + methodPath;
                            }, m -> "anon"))
                            .entrySet()
                            .stream();
                })
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        return resultMap;
    }

}
